package com.foreveross.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Date;
import java.util.Enumeration;
import java.util.zip.ZipOutputStream;

import org.apache.log4j.Logger;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipFile;

import com.foreveross.crawl.common.exception.BusinessException;

/** 
 * @ClassName: 文件操作工具类 
 * @Description: TODO
 * @author luofangyi
 * @date 2014-7-20 下午2:59:56 
 *  
 */ 
public class FileUtil {

	public static final String zipPath = new File("\\").getAbsolutePath() + "webcrawl\\";
	/**
	 * 原始文件路径
	 */
	public static final String originalFilePath = new File("\\").getAbsolutePath() + "webcrawl\\original\\";
	
	/**
	 * 备份文件路径
	 */
	private static final String bakFilePath = new File("\\").getAbsolutePath() + "webcrawl\\bak";

	private static final int buffer = 2048;
	
	public static final String zipSuffix = ".zip";
	
	/**
	 * 上传异常时的文件后缀
	 */
	public static final String exceptionSuffix = "_uploadFail";
	
	private static Logger logger = Logger.getLogger(FileUtil.class);

	/**
	 * 将DOS/Windows格式的路径转换为UNIX/Linux格式的路径。
	 * 其实就是将路径中的"\"全部换为"/"，因为在某些情况下我们转换为这种方式比较方便，
	 * 某中程度上说"/"比"\"更适合作为路径分隔符，而且DOS/Windows也将它当作路径分隔符。
	 * @param filePath 转换前的路径
	 * @return 转换后的路径
	 */
	public static String toUNIXpath(String filePath) {
		return filePath.replace('\\', '/');
	}

	/**
	 * 从文件名得到UNIX风格的文件绝对路径。
	 * @param fileName 文件名
	 * @return 对应的UNIX风格的文件路径
	 * @since 0.4
	 * @see #toUNIXpath(String filePath) toUNIXpath
	 */
	public static String getUNIXfilePath(String fileName) {
		File file = new File(fileName);
		return toUNIXpath(file.getAbsolutePath());
	}

	public static void createParseFile(String fileName) throws IOException{
		createFile(getParseFilePath(), fileName);
	}
	
	public void createSourceFile(String fileName) throws IOException{
		createFile(getSourceFilePath(), fileName);
	}
	
	/**  
	 * @Description: 创建路径
	 * @param path
	 * @author luofangyi
	 * @date 2014-7-24 上午9:51:04 
	 */ 
	private static void createPath(String path){
		File directory = new File(path);
        if(!directory.exists()){
     	   directory.mkdirs();
        }
	}

	/**  
	 * @Description: 创建文件
	 * @param fileName
	 * @param path
	 * @author luofangyi
	 * @throws IOException 
	 * @date 2014-7-20 下午3:10:13 
	 */ 
	private static void createFile(String path, String fileName) throws IOException{
		
		createPath(path);
        File file = getFile(path, fileName);        
        if(!file.exists()){
        	file.createNewFile();
        }
        if(!file.canRead()){//设置读权限
        	file.setReadable(true);
        }
        if(!file.canWrite()){//设置写权限
        	file.setWritable(true);
        }
	}
	
	private static File getFile(String path, String fileName){
		return new File(path + File.separator + fileName);
	}
	
    /**  
     * @Description: 解析数据（适配器最终获取的对象模型）保存路径
     * @return
     * @author luofangyi
     * @date 2014-7-23 下午5:13:11 
     */ 
    public static String getParseFilePath(){
    	String path = originalFilePath + "parse";
    	return getFilePath(path);
    }
    
    /**  
     * @Description: 源文件（待解析的html或json）保存路径
     * @return
     * @author luofangyi
     * @date 2014-7-23 下午5:13:53 
     */ 
    public String getSourceFilePath(){
    	String path = originalFilePath + "source";
    	return getFilePath(path);
    }
    
    /**  
     * @Description: 得到处理后（windows、linux环境下）的路径
     * @param path
     * @return
     * @author luofangyi
     * @date 2014-7-24 上午10:11:49 
     */ 
    public static String getFilePath(String path){
    	String osType = System.getProperty("os.name");
    	if(osType.toUpperCase().contains("WINDOWS")){
    		return path;
    	} else {
    		return getUNIXfilePath(path);
    	}
    }
    
    public static void writeParseFile(String fileName, String content, boolean isAppend){
    	synchronized (FileUtil.class) {
			writeFile(getParseFilePath(), fileName, content, isAppend);
		}
    }
    
    public void writeSourceFile(String fileName, String content, boolean isAppend){
    	synchronized (FileUtil.class) {
			writeFile(getSourceFilePath(), fileName, content, isAppend);
		}
    }
    
	/**  
	 * @Description: 写入文件
	 * @param path 路径
	 * @param fileName 文件名
	 * @param content 内容
	 * @param isAppend 是否追加方式写入文件
	 * @author luofangyi
	 * @date 2014-7-30 上午11:51:55 
	 */ 
	private static void writeFile(String path, String fileName, String content, boolean isAppend) {
		synchronized (FileUtil.class) {
			FileOutputStream fos = null;
			FileChannel fc = null;
			try {
				createParseFile(fileName);
				fos = new FileOutputStream(getFile(path, fileName), isAppend);
				// 第一步 获取一个通道
				fc = fos.getChannel();
				// buffer=ByteBuffer.allocate(1024);
				// 第二步 定义缓冲区
				ByteBuffer buffer = ByteBuffer.wrap(content.getBytes("utf-8"));
				// 将内容写到缓冲区
				fos.flush();
				fc.write(buffer);
			} catch (FileNotFoundException fe) {
				fe.printStackTrace();
				logger.error(fe.getMessage());
			} catch (IOException e) {
				e.printStackTrace();
				logger.error(e.getMessage());
			} finally {
				try {
					if (fos != null)
						fos.close();
					if (fc != null && fc.isOpen()) {
						fos.close();
					}
				} catch (IOException e) {
					e.printStackTrace();
					logger.error(e.getMessage());
				}
			}
		}
	}
	
	public static void unZip(String path)
	{
        int count = -1;
        int index = -1;
        String savepath = "";
		boolean flag = false;
		
		File file = null; 
        InputStream is = null;  
        FileOutputStream fos = null;  
        BufferedOutputStream bos = null;
        ZipFile zipFile = null;
        
		savepath = path.substring(0, path.lastIndexOf("\\")) + "\\";

        try
        {
        	zipFile = new ZipFile(getFilePath(path)); 

        	Enumeration<?> entries = zipFile.getEntries();
        	
            while(entries.hasMoreElements())
            { 
            	byte buf[] = new byte[buffer]; 
            	
                ZipEntry entry = (ZipEntry)entries.nextElement(); 
                
                String filename = entry.getName();
                index = filename.lastIndexOf("/");
				if(index > -1)
					filename = filename.substring(index+1);
				
                filename = savepath + filename;
                filename = getFilePath(filename);
                flag = isPics(filename);
                if(!flag)
                	continue;
                
                file = new File(filename); 
                file.createNewFile();
                
                is = zipFile.getInputStream(entry); 
                
                fos = new FileOutputStream(file); 
                bos = new BufferedOutputStream(fos, buffer);
                
                while((count = is.read(buf)) > -1)
                { 
                    bos.write(buf, 0, count ); 
                }
            }
        } catch(IOException ioe){ 
            ioe.printStackTrace(); 
            logger.error(ioe.getMessage());
        } finally{
            try {
            	if(bos != null)
            		bos.close();
            	if(fos != null)
            		fos.close(); 
            	if(is != null)
            		is.close(); 
            	if(zipFile != null)
            		zipFile.close();
			} catch (Exception e) {
				e.printStackTrace();
				logger.error(e.getMessage());
			} 
        }
    }
	
	public static boolean isPics(String filename)
	{
		boolean flag = false;
		
		if(filename.endsWith(".jpg") || filename.endsWith(".gif")  || filename.endsWith(".bmp") || filename.endsWith(".png"))
			flag = true;
		
		return flag;
	}
	
	/**  
	 * @Description: 压缩原始文件
	 * @param zipFileName 压缩文件名称
	 * @author luofangyi
	 * @date 2014-7-24 上午9:56:15 
	 */ 
	public static synchronized String zipOriginalFile(String zipFileName){
		String path = getFilePath(zipPath + zipFileName + zipSuffix);
		zip(zipFileName, getFilePath(originalFilePath));
		return path;
	}
	
	/**  
	 * @Description: 压缩备份文件
	 * @param zipFileName 压缩文件名称
	 * @author luofangyi
	 * @date 2014-7-24 上午9:59:42 
	 */ 
	public static void zipBakFile(String zipFileName){
		zip(zipFileName, getFilePath(bakFilePath));
	}
	
	/**  
	 * @Description: 压缩指定路径下文件
	 * @param zipFileName 压缩文件名称（已包含文件类型）
	 * @param path 待压缩文件路径
	 * @author luofangyi
	 * @date 2014-7-23 下午5:41:51 
	 */ 
	public static synchronized void zip(String zipFileName, String path) {
			ZipOutputStream out = null;
			File inputFile = null;
			String zipCompletePath = getFilePath(zipPath + zipFileName + zipSuffix);
			try {
				inputFile = new File(path);
				out = new ZipOutputStream(new FileOutputStream(zipCompletePath));
				zip(out, inputFile, "");
			} catch (Exception e) {
				e.printStackTrace();
				logger.error(e.getMessage());
			} finally {
				try {
					if (out != null) {
						out.close();
					}
				} catch (IOException e) {
					e.printStackTrace();
					logger.error(e.getMessage());
				}
			}
    }
	
	public static synchronized void zip(String zipFileName, File inputFile,
			String base) {
		ZipOutputStream out = null;
		try {
			out = new ZipOutputStream(new FileOutputStream(zipFileName));
			zip(out, inputFile, base);
			logger.info("zip done");
		} catch (Exception e) {
			e.printStackTrace();
			logger.error(e.getMessage());
		} finally {
			try {
				if (out != null) {
					out.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
				logger.error(e.getMessage());
			}
		}
	}
	
	private static synchronized void zip(ZipOutputStream out, File f,
			String base) {
		FileInputStream in = null;
		try {
			if (f.isDirectory()) {
				File[] fl = f.listFiles();
				out.putNextEntry(new org.apache.tools.zip.ZipEntry(base + "/"));
				base = base.length() == 0 ? "" : base + "/";
				for (int i = 0; i < fl.length; i++) {
					zip(out, fl[i], base + fl[i].getName());
				}
			} else {
				out.putNextEntry(new org.apache.tools.zip.ZipEntry(base));
				in = new FileInputStream(f);
				int b;
				while ((b = in.read()) != -1) {
					out.write(b);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
			logger.error(e.getMessage());
		} finally {
			try {
				if (in != null) {
					in.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
				logger.error(e.getMessage());
			}
		}
	}
	
	public static void copyFile(File sourceFile, File targetFile) {
		BufferedInputStream inBuff = null;
        BufferedOutputStream outBuff = null;
        try {
            // 新建文件输入流并对它进行缓冲
            inBuff = new BufferedInputStream(new FileInputStream(sourceFile));

            // 新建文件输出流并对它进行缓冲
            outBuff = new BufferedOutputStream(new FileOutputStream(targetFile));

            // 缓冲数组
            byte[] b = new byte[1024 * 5];
            int len;
            while ((len = inBuff.read(b)) != -1) {
                outBuff.write(b, 0, len);
            }
            // 刷新此缓冲的输出流
            outBuff.flush();
        } catch (Exception e) {
			e.printStackTrace();
			logger.error(e.getMessage());
		} finally {
            // 关闭流
            try {
				if (inBuff != null)
				    inBuff.close();
				if (outBuff != null)
				    outBuff.close();
			} catch (Exception e) {
				e.printStackTrace();
				logger.error(e.getMessage());
			}
        }
	}
	
	/**  
	 * @Description: 拷贝文件夹
	 * @param sourceDir 原文件路径
	 * @param targetDir 目标文件路径
	 * @author luofangyi
	 * @date 2014-7-24 上午10:18:31 
	 */ 
	public void copyDirectiory(String sourceDir, String targetDir){
		sourceDir = getFilePath(sourceDir);
		targetDir = getFilePath(targetDir);
		createPath(targetDir);//创建备份文件保存路径
		File[] files = (new File(sourceDir)).listFiles();//获取原文件
		for (File file : files) {
			if (file.isDirectory()) {
				String childSourceDir = sourceDir + "\\" + file.getName();
				String childTargetDir = targetDir + "\\" + file.getName();
				copyDirectiory(getFilePath(childSourceDir), getFilePath(childTargetDir));
			} else if (file.isFile()){
				File targetFile = new File(new File(targetDir).getAbsolutePath() + File.separator + file.getName());
				copyFile(file, targetFile);
			}
		}
	}
	
	/**  
	 * @Description: 重命名文件
	 * @param oldName
	 * @param newName
	 * @author luofangyi
	 * @throws BusinessException 
	 * @date 2014-7-31 下午2:17:05 
	 */ 
	public static void renameFile(String oldName, String newName) throws BusinessException{
		if(!oldName.equals(newName)){
			File oldFile = new File(getFilePath(zipPath + oldName + zipSuffix));
			File newFile = new File(getFilePath(zipPath + newName + zipSuffix));
			if(newFile.exists()){
				throw new BusinessException("已存在与新文件名重名的文件");
			}
			oldFile.renameTo(newFile);
		}
	}
	
	/**  
	 * @Description: 删除文件或文件夹
	 * @param path
	 * @author luofangyi
	 * @date 2014-8-6 下午5:57:02 
	 */ 
	public synchronized static void deleteForlder(String path){
		File file = new File(getFilePath(path));
		if(file.exists()){
			if(file.isFile()){
				deleteFile(file);
			} else if(file.isDirectory()){
				deleteDirectory(file);
			}
		}
	}
	
	public synchronized static void deleteParseForlder(){
		deleteForlder(getFilePath(originalFilePath));
	}
	
	/**  
	 * @Description: 删除文件
	 * @param file
	 * @author luofangyi
	 * @date 2014-8-6 下午5:59:06 
	 */ 
	private synchronized static void deleteFile(File file){
		file.delete();
	}
	
	/**  
	 * @Description: 删除文件夹
	 * @param file
	 * @author luofangyi
	 * @date 2014-8-6 下午6:11:12 
	 */ 
	private synchronized static void deleteDirectory(File file){
		if(file.listFiles().length == 0){
			file.delete();
		} else {
			File[] files = file.listFiles();
			for(File f : files){
				if(f.isDirectory()){
					deleteDirectory(f);
				}
				deleteFile(file);
			}
		}
	}
	
	public static long getFileModifiedTime(String filePath){
		File file = new File(getFilePath(filePath));
		if(file.exists())
			return  file.lastModified();
		return -1;
	}
	
	/**  
	 * @Description: 判断指定文件是否达到超时操作条件
	 * @param path 文件路径
	 * @param intervalTime 间隔时间
	 * @return
	 * @author luofangyi
	 * @throws BusinessException 
	 * @date 2014-8-10 上午9:18:10 
	 */ 
	public static boolean isOperatorByTimeout(String path, double intervalTime) throws BusinessException {
		boolean flag = false;
		long curTime = new Date().getTime();
		long modifiedTime = FileUtil.getFileModifiedTime(getFilePath(path));
		if(modifiedTime < 0){
			throw new BusinessException("无法找到指定文件");
		}
		if(curTime - modifiedTime >= (intervalTime * 1000 * 60 * 60)){
			flag = true;
		}
		
		return flag;
	}
    
    public static void main(String[] args){
//    	System.out.println(filePath);
    	try {
//			createParseFile("test.txt");
//			writeParseFile("test.txt", "jaiosf", true);
//			writeParseFile("test.txt", "kkkkkkkkkkkkkkkkkkk", true);
//			writeParseFile("test.txt", "bbbbbbbbbbbbbbbbbbbbbbbbbbb", true);
//			
//			createSourceFile("source.txt");
//			writeSourceFile("source.txt", "jaiosf", true);
//			writeSourceFile("source.txt", "12333333333333333", true);
//			writeSourceFile("source.txt", "4325341", true);
//			
//			zipOriginalFile("original");
			renameFile("original", "my");
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    }
}
